﻿
using Microsoft.VisualStudio.TestTools.UnitTesting;
using static FlyIL.OperandMaker;
using static FlyIL.AssemblerRegisters;
using FlyIL.Advance;
using FlyIl.AdvanceTests;
using FlyIL.Emu;

namespace FlyIL.Optimizer.Tests
{
    [TestClass()]
    public class 化简集中测试
    {
        [TestMethod()]
        public void BranchNopTest()
        {
            Context vcontext;

            vcontext = new Context(false, 0);
            vcontext.Make().call(3, 5);
            vcontext.Make().nop();
            vcontext.Make().pop(R1D);               // nop
            var cpu = TestHelper.Run32(vcontext);

            vcontext.SimplifyOnce();
            vcontext.ClearNop();
            Assert.AreEqual(vcontext.Entry.Opt, Opt.jmp);

            Cpu cpu2 = TestHelper.Run32(vcontext);
            Assert.AreEqual(cpu, cpu2);


        }




        [TestMethod()]
        public void SimplifyTest()
        {
            Context vcontext;

            //vcontext = new Vcontext(false, 0);
            //vcontext.Make().lea(Esp, (Esp - 8));
            //vcontext.Make().lea(Esp, (Esp + 6));
            //vcontext.Make().push(R1D);
            //vcontext.Make().push(R3D);
            //vcontext.Make().push(R4D);
            //vcontext.Make().push(R2D);
            //vcontext.Make().push(Esp);
            //vcontext.Make().push(R5D);
            //vcontext.Make().push(R6D);
            //vcontext.Make().push(R7D);

            //vcontext.Make().mov(_dword_ptr[Esp + 0x1e], R6D);
            //vcontext.CheckSimplifyOnce();
            //vcontext.ClearNop();
            //Assert.AreEqual(vcontext.Codes.Count, 1);



            {

                vcontext = new Context(false, 0);
                vcontext.Make().push((uint)1111);       // nop
                vcontext.Make().pop(R1D);               // nop
                vcontext.Make().mov(R1D, 111);
                var cpu = TestHelper.Run32(vcontext);

                vcontext.SimplifyOnce();
                vcontext.ClearNop();
                Assert.AreEqual(vcontext.Codes.Count, 1);
                Cpu cpu2 = TestHelper.Run32(vcontext);
                Assert.AreEqual(cpu, cpu2);

            }

            {

                vcontext = new Context(false, 0);
                vcontext.Make().push((uint)1111);               // nop
                vcontext.Make().mov(_dword_[Esp + 8], 1);    // fix
                vcontext.Make().pop(R1D);                       // nop
                vcontext.Make().mov(_dword_[Esp + 0], 1);
                vcontext.Make().mov(R1D, 2);
                var cpu = TestHelper.Run32(vcontext);

                vcontext.SimplifyOnce();
                vcontext.ClearNop();
                Assert.AreEqual(vcontext.Codes.Count, 3);
                Cpu cpu2 = TestHelper.Run32(vcontext);
                Assert.AreEqual(cpu, cpu2);
            }


            {

                vcontext = new Context(false);
                vcontext.Make().push((uint)1111);
                vcontext.Make().mov(R1D, 1);
                vcontext.Make().mov(R1D, 2);
                vcontext.Make().mov(R1D, 3);
                vcontext.Make().pop(R1D);
                vcontext.Make().mov(R1D, 2);    // 以上均 nop 
                var cpu = TestHelper.Run32(vcontext);

                vcontext.SimplifyOnce();
                vcontext.ClearNop();
                Assert.AreEqual(vcontext.Codes.Count, 1);
                Cpu cpu2 = TestHelper.Run32(vcontext);
                Assert.AreEqual(cpu, cpu2);


            }

            /*
             * 一次 赋新值之前 ， 如果该参数 ， 没有有效传递（即做为第二参数） 
             * 那么可以认为，在这之前的 所以计算，以及赋值，都是无意义的 
             * 
             */


            {

                vcontext = new Context(false);
                vcontext.Make().mov(R1D, 1);        //nop
                vcontext.Make().sub(R1W, 1);        //nop
                vcontext.Make().add(R1L, R2H);      //nop
                vcontext.Make().xor(R1L, 122);      //nop
                vcontext.Make().mov(R1D, 2);
                var cpu = TestHelper.Run32(vcontext);

                vcontext.SimplifyOnce();
                vcontext.ClearNop();
                Assert.AreEqual(vcontext.Codes.Count, 1);
                Cpu cpu2 = TestHelper.Run32(vcontext);
                Assert.AreEqual(cpu, cpu2);
            }
            /// 带一次无效 传值  

            {

                vcontext = new Context(false, 0);
                vcontext.Make().mov(R1D, 1);        //nop
                vcontext.Make().mov(R2D, R1D);      //nop
                vcontext.Make().xor(R1L, 122);      //nop
                vcontext.Make().mov(R2D, 222);      // 前面的赋值 无意义 
                vcontext.Make().mov(R1D, 2);        // 同上 
                var cpu = TestHelper.Run32(vcontext);

                vcontext.SimplifyBetween();
                vcontext.ClearNop();
                Assert.AreEqual(vcontext.Codes.Count, 2);
                Cpu cpu2 = TestHelper.Run32(vcontext);
                Assert.AreEqual(cpu, cpu2);

            }

            /// 带一次无效压栈 , 值传递 

            {

                vcontext = new Context(false, 0);
                vcontext.Make().mov(R1D, R2D);        //nop
                vcontext.Make().push(R1D);          //push 1
                vcontext.SimplifyOnce();
                vcontext.Make().xor(R1L, 122);      //nop
                vcontext.Make().mov(R1D, 2);
                var cpu = TestHelper.Run32(vcontext);

                vcontext.SimplifyOnce();
                vcontext.ClearNop();
                Assert.AreEqual(vcontext.Codes.Count, 2);
                Cpu cpu2 = TestHelper.Run32(vcontext);
                Assert.AreEqual(cpu, cpu2);
            }


            {

                vcontext = new Context(false, 0);
                vcontext.Make().mov(R1, 1);
                vcontext.Make().mov(R1D, 2);
                var cpu = TestHelper.Run32(vcontext);

                vcontext.SimplifyOnce();
                vcontext.ClearNop();
                Assert.AreEqual(vcontext.Codes.Count, 2);
                Cpu cpu2 = TestHelper.Run32(vcontext);
                Assert.AreEqual(cpu, cpu2);

            }

            {

                vcontext = new Context(false, 0);
                vcontext.Make().push(R1D);
                vcontext.Make().pop(R1D);
                var cpu = TestHelper.Run32(vcontext);

                vcontext.SimplifyOnce();
                vcontext.ClearNop();
                Assert.AreEqual(vcontext.Codes.Count, 0);
                Cpu cpu2 = TestHelper.Run32(vcontext);
                Assert.AreEqual(cpu, cpu2);


            }

        }

    }
}